package org.brakepedal.server.config;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.scheduling.annotation.SchedulingConfigurer;

import java.util.concurrent.*;

/**
 * Date: 2023/2/5 21:50
 */
@Slf4j
@Setter
@Getter
@ToString
@Configuration
@RequiredArgsConstructor
public class ThreadPoolConfig {
    @Primary
    @Qualifier
    @Bean(value = "taskExecutor", destroyMethod = "close")
    public ExecutorService virtualThreadTaskExecutor(@Qualifier("virtualThreadFactory") ThreadFactory factory) {
        return Executors.newThreadPerTaskExecutor(factory);
    }

    @Bean
    public ThreadFactory virtualThreadFactory() {
        return Thread.ofVirtual()
               .name("v-t-executor-",0)
               .inheritInheritableThreadLocals(true)
               .uncaughtExceptionHandler((thread, e)->{
                    log.error("Thread: [{}] throw exception", thread.getName(),e);
                })
                .factory();
    }

    @Bean(destroyMethod = "close")
    public ExecutorService applicationVirtualThreadExecutor() {
        ThreadFactory factory = Thread.ofVirtual()
                .name("app-executor-",0)
                .inheritInheritableThreadLocals(true)
                .uncaughtExceptionHandler((thread, e)->{
                    log.error("Thread: [{}] throw exception", thread.getName(),e);
                })
                .factory();
        return Executors.newThreadPerTaskExecutor(factory);
    }
    @Bean
    public AsyncTaskExecutor applicationTaskExecutor() {
        return new TaskExecutorAdapter(applicationVirtualThreadExecutor());
    }

    @Bean
    public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
        return protocolHandler -> {
            protocolHandler.setExecutor(applicationVirtualThreadExecutor());
        };
    }

//    @ConditionalOnBean(SchedulingConfigurer.class)
    @Lazy
    @Bean(name = "scheduledPoolTaskExecutor", destroyMethod = "shutdown")
    public ScheduledThreadPoolExecutor scheduledThreadPoolExecutor(@Qualifier("virtualThreadFactory") ThreadFactory threadFactory) {
        // 第一个参数：核心线程数
        // 第二个参数：线程工厂(此处用来设置线程名)
        // 第三次参数：饱和策略
        // 饱和策略
        // AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常
        // CallerRunsPolicy:若已达到待处理队列长度，将由主线程直接处理请求
        // DiscardOldestPolicy:抛弃旧的任务；会导致被丢弃的任务无法再次被执行
        // DiscardPolicy:抛弃当前任务；会导致被丢弃的任务无法再次被执行
        return new ScheduledThreadPoolExecutor(
                0,
                threadFactory,
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }
}
